30  K-Means算法 股市波动聚类

30.1 引言无监督学习与聚类分析

K-Means算法是经典的聚类算法: - 无监督学习: 不需要标签 - 划分式聚类: 将数据分为K个簇 - 金融应用: 股票分类、风险分组

30.2 算法原理

K-Means目标: 最小化簇内平方和(SSE)

\[ SSE = \sum_{i=1}^{K}\sum_{x \in C_i} ||x - \mu_i||^2 \]

其中: - \(K\): 簇的数量 - \(C_i\): 第i个簇 - \(\mu_i\): 第i个簇的质心(均值)

算法步骤: 1. 随机初始化K个质心 2. 将每个样本分配到最近的质心 3. 重新计算每个簇的质心 4. 重复2-3直到收敛

30.3 股指波动聚类

列表 30.1
# 注:case3.1.xlsx数据文件本地没有,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd  # 导入Pandas数据分析库
from sklearn.cluster import KMeans  # 导入Scikit-learn的KMeans模块
import matplotlib.pyplot as plt  # 导入Matplotlib绑图库
data = pd.read_excel("case3.1.xlsx")  # 从Excel文件读取数据存入data
SSE = []  # 定义列表SSE
cols = data.iloc[:, 2:]  # 提取数值型特征列(跳过前两列的非数值信息)
for k in range(1,10):  # 遍历range(1,10)中的每个k
  estimator = KMeans(n_clusters=k)  # 初始化K-Means聚类模型
    estimator.fit(cols)  # 在数据上训练estimator模型
    SSE.append(estimator.inertia_)  # 将当前K值的簇内误差平方和(SSE)添加到列表
plt.plot(range(1,10), SSE,'*-')  # 绑制折线图
plt.title('Elbow Method')  # 设置图表标题
plt.xlabel('K Clusters')  # 设置X轴标签
plt.ylabel('SSE')  # 设置Y轴标签
plt.savefig("1.png") #过程展示一
data1=data.drop('股指',axis=1)  # 删除指定行或列
clu = KMeans(n_clusters=3,random_state=30)  # 初始化K-Means聚类模型
clu.fit(data1)  # 在数据上训练clu模型
label = clu.labels_  # 获取聚类模型对每个样本的簇标签
print(label)# 结果展示

30.4 执行聚类分析

列表 30.2
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行

# ==================== 准备聚类特征数据 ====================
data_features = data.drop('股指', axis=1)  # 删除非数值列'股指',axis=1表示按列删除
# 只保留数值型特征用于聚类分析

# ==================== 执行K-Means聚类 ====================
kmeans = KMeans(n_clusters=3, random_state=30)  # 创建K-Means模型,设置聚类数为3
# random_state=30设置随机种子,与之前不同会得到不同的初始质心
kmeans.fit(data_features)  # 在数据上拟合K-Means模型

# ==================== 获取聚类结果 ====================
labels = kmeans.labels_  # 获取每个样本的聚类标签(0, 1, 2)
# labels_属性存储了每个数据点所属的簇编号

# ==================== 获取聚类质心 ====================
centroids = kmeans.cluster_centers_  # 获取每个簇的质心坐标
# cluster_centers_属性存储了K个质心的位置

# ==================== 将聚类标签添加到原数据 ====================
data['Cluster'] = labels  # 在原数据中新增Cluster列,存储聚类结果
# 这样可以方便地按簇进行后续分析

print('聚类标签:')  # 输出标题
print(labels)  # 显示每个样本的聚类标签

print('\n各簇样本数:')  # 输出标题
print(pd.Series(labels).value_counts().sort_index())  # 统计每个簇的样本数
# pd.Series(labels).value_counts()统计每个标签出现的次数
# sort_index()按簇编号排序,使输出更清晰

print('\n聚类质心:')  # 输出标题
for i, centroid in enumerate(centroids):  # 遍历每个簇的质心
    print(f'\n{i}质心:')  # 输出簇编号
    for j, value in enumerate(centroid):  # 遍历质心的每个维度
        print(f'  特征{j+1}: {value:.4f}')  # 输出每个特征维度的质心坐标,保留4位小数

30.5 结果解读

列表 30.3
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行

# ==================== 按簇统计特征均值 ====================
cluster_stats = data.groupby('Cluster').mean()  # 按簇分组,计算各特征的平均值
print('各簇平均特征:')  # 输出标题
print(cluster_stats)  # 显示每个簇的特征均值
# 这有助于理解每个簇的特点和商业含义

# ==================== 可视化聚类结果 ====================
plt.figure(figsize=(10, 6))  # 创建10x6英寸的画布
scatter = plt.scatter(
    data_features.iloc[:, 0],  # x轴为第1个特征
    data_features.iloc[:, 1],  # y轴为第2个特征
    c=labels,  # 颜色由聚类标签决定
    cmap='viridis',  # 使用viridis配色方案
    s=100,  # 散点大小为100
    alpha=0.6  # 透明度为0.6
)
plt.colorbar(scatter, label='Cluster')  # 添加颜色条,显示簇编号
plt.scatter(
    centroids[:, 0],  # 质心的x坐标
    centroids[:, 1],  # 质心的y坐标
    c='red',  # 质心颜色为红色
    marker='X',  # 质心标记为X形
    s=300,  # 质心大小为300
    linewidths=2,  # 边框线宽为2
    edgecolors='black',  # 边框颜色为黑色
    label='质心'  # 图例标签
)
plt.title('K-Means聚类结果', fontsize=14)  # 设置图表标题
plt.xlabel('特征1', fontsize=12)  # 设置x轴标签
plt.ylabel('特征2', fontsize=12)  # 设置y轴标签
plt.legend()  # 显示图例
plt.grid(True, alpha=0.3)  # 显示网格线
plt.tight_layout()  # 自动调整布局
plt.show()  # 显示图表

30.6 应用场景

金融中的聚类应用: 1. 股票分类: 根据波动率、收益率等特征分组 2. 客户分层: RFM模型之外的补充 3. 风险分组: 识别高风险组合 4. 异常检测: 远离所有质心的点可能是异常